﻿#region 版权信息
// ------------------------------------------------------------------------------
// Copyright: (c) 2029  耍嗨科技（成都）有限公司 - Amm
// 项目名称：$SOLUTION/$.Amm.Common
// 文件名称：ConvertExtensions.cs
// 创建时间：2020093011:20
// 更改时间：2020093011:20
//  ------------------------------------------------------------------------------
#endregion

using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using Colorful.Furniture.ResultManagement;
using System.Xml.Serialization;
using Newtonsoft.Json;

namespace Colorful.Furniture.Extensions
{
    /// <summary>
    ///  数据转换
    /// </summary>
    public static class ConvertExtensions
    {
        public static int ToInt(this object thisValue)
        {
            int reval = 0;
            if (thisValue == null) return 0;
            if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return reval;
        }

        public static int ToInt(this object thisValue, int errorValue)
        {
            int reval;
            if (thisValue != null && thisValue != DBNull.Value && int.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }

        public static long ToLong(this object s)
        {
            if (s == null || s == DBNull.Value)
                return 0L;

            long.TryParse(s.ToString(), out long result);
            return result;
        }

        public static long ToLong(this object s, long defaultValue)
        {
            if (s == null || s == DBNull.Value)
                return 0L;

            var valid = long.TryParse(s.ToString(), out long result);

            return valid ? result : defaultValue;
        }

        public static double ToMoney(this object thisValue)
        {
            double reval;
            if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return 0;
        }

        public static double ToMoney(this object thisValue, double errorValue)
        {
            double reval;
            if (thisValue != null && thisValue != DBNull.Value && double.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }

        public static string ToString(this object thisValue)
        {
            if (thisValue != null) return thisValue.ToString().Trim();
            return "";
        }

        public static string ToString(this object thisValue, string errorValue)
        {
            if (thisValue != null) return thisValue.ToString().Trim();
            return errorValue;
        }

        /// <summary>
        /// 转换成Double/Single
        /// </summary>
        /// <param name="s"></param>
        /// <param name="digits">小数位数</param>
        /// <returns></returns>
        public static double ToDouble(this object s, int? digits = null)
        {
            if (s == null || s == DBNull.Value)
                return 0d;

            double.TryParse(s.ToString(), out double result);

            if (digits == null)
                return result;

            return Math.Round(result, digits.Value);
        }

        public static decimal ToDecimal(this object thisValue)
        {
            decimal reval;
            if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return 0;
        }

        public static decimal? ToNullableDecimal(this object thisValue)
        {
            decimal reval;
            if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return default;
        }

        public static decimal ToDecimal(this object thisValue, decimal errorValue)
        {
            decimal reval;
            if (thisValue != null && thisValue != DBNull.Value && decimal.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }

        public static DateTime ToDateTime(this object thisValue)
        {
            DateTime reval = DateTime.MinValue;
            if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
            {
                reval = Convert.ToDateTime(thisValue);
            }
            return reval;
        }

        public static DateTime? ToNullableDateTime(this object thisValue)
        {
            try
            {
                if (thisValue == null)
                    return null;

                return Convert.ToDateTime(thisValue);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                return null;
            }
        }

        public static DateTime ToDateTime(this object thisValue, DateTime errorValue)
        {
            DateTime reval;
            if (thisValue != null && thisValue != DBNull.Value && DateTime.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return errorValue;
        }

        /// <summary>
        ///  时间戳转时间格式
        /// </summary>
        /// <param name="milliseconds"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this long milliseconds)
        {
            var misString = milliseconds.ToString();

            var mis = misString.Length > 10 ? misString.Substring(0, 10) : misString;

            return DateTimeExtensions.TimestampStart.AddSeconds(mis.ToLong());
        }


        public static bool ToBool(this object thisValue)
        {
            bool reval = false;
            if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval))
            {
                return reval;
            }
            return reval;
        }

        public static byte ToByte(this object s)
        {
            if (s == null || s == DBNull.Value)
                return 0;

            byte.TryParse(s.ToString(), out byte result);
            return result;
        }

        /// <summary>
        ///  列表转字符串
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="list">集合</param>
        /// <param name="format">格式化</param>
        /// <returns></returns>
        public static string ListToString<T>(this List<T> list, string format = ",")
        {
            if (list == null || !list.Any())
                return default;

            return string.Join(format, list);
        }

        /// <summary>
        ///  字符串转列表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="input"></param>
        /// <param name="format"></param>
        /// <returns></returns>
        public static List<T> StringToList<T>(this string input, string format = ",")
        {
            return string.IsNullOrWhiteSpace(input)
                ? default
                : input.Split(format, StringSplitOptions.RemoveEmptyEntries)
                    .Select(x => (T)Convert.ChangeType(x, typeof(T)))
                    .ToList();
        }

        /// <summary>
        ///  泛型转换成get请求参数
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string GenericToGetQueryData<T>(this T input) where T : class, new()
        {
            if (input == null)
                return string.Empty;

            //反射
            var properties = input.GetType().GetProperties();

            //组合参数
            var queryParamList = properties
                .Select(propertyInfo => $"{propertyInfo.Name}={propertyInfo.GetValue(input, null)}")
                .ToList();

            return string.Join("&", queryParamList);
        }

        /// <summary>
        ///  xml转换成实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="responseXml">xml字符串</param>
        /// <param name="xmlRootElementName">xml root节点的名字，针对xml根节点不标准的情况</param>
        /// <returns></returns>
        public static T XmlStringToGeneric<T>(this string responseXml, string xmlRootElementName = "response") where T : class, new()
        {
            if (string.IsNullOrWhiteSpace(responseXml))
                return default;

            using var reader = XmlReader.Create(new StringReader(responseXml));

            var serializer = new XmlSerializer(typeof(T), new XmlRootAttribute(xmlRootElementName));
            var outputDto = serializer.Deserialize(reader) as T;
            return outputDto;
        }

        /// <summary>
        ///   字符串转换成泛型
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="input"></param>
        /// <param name="jsonSerializerSettings"></param>
        /// <returns></returns>
        public static T StringToGeneric<T>(this string input, JsonSerializerSettings jsonSerializerSettings = null) where T : new()
        {
            try
            {
                return !string.IsNullOrWhiteSpace(input)
                    ? jsonSerializerSettings != null ? JsonConvert.DeserializeObject<T>(input, jsonSerializerSettings) : JsonConvert.DeserializeObject<T>(input)
                    : new T();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);

                return new T();
            }
        }

        /// <summary>
        ///   字符串转换成泛型
        /// </summary>
        /// <typeparam name="T">序列化对象</typeparam>
        /// <param name="input">请求体</param>
        /// <param name="jsonSerializerSettings">序列化设置</param>
        /// <returns></returns>
        public static string GenericToString<T>(this T input, JsonSerializerSettings jsonSerializerSettings = null) where T : class
        {
            try
            {
                return input == null || input == DBNull.Value
                    ? string.Empty
                    : jsonSerializerSettings != null ? JsonConvert.SerializeObject(input, jsonSerializerSettings) : JsonConvert.SerializeObject(input);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
                return string.Empty;
            }
        }

        /// <summary>
        ///  保留两位小数（四舍五入）
        /// </summary>
        /// <param name="input"></param>
        /// <param name="decimals"></param>
        /// <returns></returns>
        public static decimal ToRounding(this decimal? input, int decimals = 2)
        {
            return input.HasValue ?
             Math.Round(input.Value, decimals, MidpointRounding.AwayFromZero)
                : 0;
        }

        /// <summary>
        /// 保留两位小数（四舍五入）
        /// </summary>
        /// <param name="input"></param>
        /// <param name="decimals"></param>
        /// <returns></returns>
        public static decimal ToRounding(this decimal input, int decimals = 2)
        {
            return
                Math.Round(input, decimals, MidpointRounding.AwayFromZero);
        }

        /// <summary>
        ///  保留两位小数（四舍五入）,如果是负数则为0
        /// </summary>
        /// <param name="input"></param>
        /// <param name="decimals"></param>
        /// <returns></returns>
        public static decimal ToRoundingNegativeToZero(this decimal? input, int decimals = 2)
        {
            var returnValue = input.HasValue ?
                Math.Round(input.Value, decimals, MidpointRounding.AwayFromZero)
                : 0;

            return returnValue < 0 ? 0 : returnValue;
        }

        /// <summary>
        ///  保留两位小数（四舍五入）,如果是负数则为0
        /// </summary>
        /// <param name="input"></param>
        /// <param name="decimals"></param>
        /// <returns></returns>
        public static decimal ToRoundingNegativeToZero(this decimal input, int decimals = 2)
        {
            var returnValue = Math.Round(input, decimals, MidpointRounding.AwayFromZero);

            return returnValue < 0 ? 0 : returnValue;
        }

        /// <summary>
        ///  保留两位小数（只入）
        /// </summary>
        /// <param name="input"></param>
        /// <param name="decimals"></param>
        /// <returns></returns>
        public static decimal ToRoundingOnlyEnter(this decimal? input, int decimals = 2)
        {
            return input.HasValue ?
                Math.Round(input.Value, decimals, MidpointRounding.ToEven)
                : 0;
        }

        /// <summary>
        ///  保留两位小数（只舍）
        /// </summary>
        /// <param name="input"></param>
        /// <param name="decimals"></param>
        /// <returns></returns>
        public static decimal ToRoundingOnlyTruncation(this decimal? input, int decimals = 2)
        {
            var value = input ?? 0;

            var c = Math.Pow(10, decimals);
            var s = Math.Truncate(value * (decimal)c);

            return Math.Round(s / 100, decimals);
        }

        /// <summary>
        ///  转换成decimal
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static decimal? ToZeroDecimal(this decimal? input)
        {
            return !input.HasValue ? null : Math.Round(input.Value);
        }

        /// <summary>
        ///  保留两位小数（只舍）
        /// </summary>
        /// <param name="input"></param>
        /// <param name="decimals"></param>
        /// <returns></returns>
        public static decimal ToRoundingOnlyTruncation(this decimal input, int decimals = 2)
        {
            var value = input;

            var c = Math.Pow(10, decimals);
            var s = Math.Truncate(value * (decimal)c);

            return Math.Round(s / 100, decimals);
        }

        /// <summary>
        /// 按小数位进位不管保留位数后面是不是大于5都进位
        /// </summary>
        /// <param name="input"></param>
        /// <param name="decimals"></param>
        /// <returns></returns>
        public static decimal ToRound(this decimal? input, int decimals = 2)
        {
            var value = input ?? 0;

            var c = Math.Pow(10, decimals);
            var s = Math.Truncate(value * (decimal)c);
            if (s < value * (decimal)c)
            {
                s += 1;
            }
            return Math.Round(s / 100, decimals);
        }

        /// <summary>
        /// 按小数位进位不管保留位数后面是不是大于5都进位
        /// </summary>
        /// <param name="input"></param>
        /// <param name="decimals"></param>
        /// <returns></returns>
        public static decimal ToRound(this decimal input, int decimals = 2)
        {
            var value = input;

            var c = Math.Pow(10, decimals);
            var s = Math.Truncate(value * (decimal)c);
            if (s < value * (decimal)c)
            {
                s += 1;
            }
            return Math.Round(s / 100, decimals);
        }

        /// <summary>
        ///  金额转换成大写
        /// </summary>
        /// <param name="amount"></param>
        /// <returns></returns>
        public static string AmountToCapitalized(this decimal amount)
        {
            //将小写金额转换成大写金额
            string[] myScale = { "分", "角", "圆", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "兆", "拾", "佰", "仟" };
            string[] myBase = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" };
            string moneyStr = "";
            var isPoint = false;
            var moneyDigital = amount.ToString(CultureInfo.InvariantCulture);
            if (moneyDigital.IndexOf(".", StringComparison.Ordinal) != -1)
            {
                moneyDigital = moneyDigital.Remove(moneyDigital.IndexOf(".", StringComparison.Ordinal), 1);
                isPoint = true;
            }
            for (var i = moneyDigital.Length; i > 0; i--)
            {
                var myData = Convert.ToInt16(moneyDigital[moneyDigital.Length - i].ToString());
                moneyStr += myBase[myData];
                if (isPoint)
                {
                    moneyStr += myScale[i - 1];
                }
                else
                {
                    moneyStr += myScale[i + 1];
                }
            }
            while (moneyStr.Contains("零零"))
                moneyStr = moneyStr.Replace("零零", "零");
            moneyStr = moneyStr.Replace("零亿", "亿");
            moneyStr = moneyStr.Replace("亿万", "亿");
            moneyStr = moneyStr.Replace("零万", "万");
            moneyStr = moneyStr.Replace("零仟", "零");
            moneyStr = moneyStr.Replace("零佰", "零");
            moneyStr = moneyStr.Replace("零拾", "零");
            while (moneyStr.Contains("零零"))
                moneyStr = moneyStr.Replace("零零", "零");
            moneyStr = moneyStr.Replace("零圆", "圆");
            moneyStr = moneyStr.Replace("零角", "");
            moneyStr = moneyStr.Replace("零分", "");
            moneyStr = moneyStr + "整";
            return moneyStr;
        }


        #region ==字节转换==
        /// <summary>
        /// 转换为16进制
        /// </summary>
        /// <param name="bytes"></param>
        /// <param name="lowerCase">是否小写</param>
        /// <returns></returns>
        public static string ToHex(this byte[] bytes, bool lowerCase = true)
        {
            if (bytes == null)
                return null;

            var result = new StringBuilder();
            var format = lowerCase ? "x2" : "X2";
            for (var i = 0; i < bytes.Length; i++)
            {
                result.Append(bytes[i].ToString(format));
            }

            return result.ToString();
        }

        /// <summary>
        /// 16进制转字节数组
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static byte[] HexToBytes(this string s)
        {
            if (s.IsNull())
                return null;
            var bytes = new byte[s.Length / 2];

            for (int x = 0; x < s.Length / 2; x++)
            {
                int i = (Convert.ToInt32(s.Substring(x * 2, 2), 16));
                bytes[x] = (byte)i;
            }

            return bytes;
        }

        /// <summary>
        /// 转换为Base64
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToBase64(this byte[] bytes)
        {
            if (bytes == null)
                return null;

            return Convert.ToBase64String(bytes);
        }

        #endregion
    }
}